/**
 * 包含基本的增删改查功能
 */
import modelExtend from 'dva-model-extend';
import { message } from 'antd';
import { pageModel } from './common';
import { isSuccess } from '../configs/error';

export default function createModel(model, query, create, remove, update) {
	const base = modelExtend(pageModel, {
		namespace: 'base',

		state: {
			list: [],
			versionList: null,
			currentItem: null,
			selectedRowKeys: [],
			total: 0,
			page: 1,
			creating: false
		},

		effects: {
			*query({ payload = {}, resetSelectedRowKeys = false }, { call, put }) {
				if (payload && payload.current) {
					yield put({
						type: 'set',
						payload: {
							page: payload.current
						}
					});
				}
				const data = yield call(query, payload);
				if (isSuccess(data)) {
					const resultData = data.data;
					yield put({
						type: 'set',
						payload: {
              ...resetSelectedRowKeys ? { selectedRowKeys: [] } : null,
							list: resultData.records,
							total: resultData.total,
							pageSize: resultData.size,
							current: resultData.current,
						},
					});
				}
			},

			*'delete'({ id }, { call, put, select }) {
				const list = yield select(state => state[model.namespace].list);
				const res = yield call(remove, [id]);
				if (isSuccess(res)) {
					message[res.data.includes('成功') ? 'success' : 'error'](res.data);
					yield put({ type: 'remove', id });
					yield put({
						type: 'query',
						payload: {},
					});
				} else {
					message.error(res.massage);
					// yield put({ type: 'list', list });
				}
			},

			*multiDelete({ ids }, { call, put, select }) {
				const res = yield call(remove, ids);
				if (isSuccess(res)) {
					message[res.data.includes('成功') ? 'success' : 'error'](res.data);
					yield put({
						type: 'query',
						payload: {},
					});
					yield put({
						type: 'updateState',
						payload: {
							selectedRowKeys: [],
						}
					});
				} else {
					message.error(res.message);
				}
			},

			*create({ payload }, { select, call, put, race }) {
				const { list, creating } = yield select(state => ({ list: state[model.namespace].list, creating: state[model.namespace].creating }));
				if (creating) {
					message.warning('请等待上一次创建成功');
					return;
				}
				yield put({ type: 'add', payload });
				yield put({ type: 'set', creating: true });
				const per = { ...payload };
				delete per.id;
				const { res, timeout } = yield race({ // 超时控制
					res: call(create, per),
					timeout: call(delay)
				});
				yield put({ type: 'set', creating: false });
				if (isSuccess(res)) {
					// yield put({ type: 'updateOne', payload: { ...payload, ...res.data } });
					yield put({ type: 'query' });
				} else {
					yield put({ type: 'edit', payload });
					yield put({ type: 'list', list });
					if (timeout) {
						message.error('任务超时');
					}
				}
			},

			*update({ payload }, { select, call, put }) {
				const old = yield select(state => state[model.namespace].list.find(t => t.id === payload.id));
				yield put({ type: 'updateOne', payload });
				const res = yield call(update, payload);
				if (isSuccess(res)) {
					message.success('更新成功');
					yield put({ type: 'updateSuccess', payload });
					return;
				} else {
					yield put({ type: 'updateOne', payload: old });
				}
			},

		},

		reducers: {
			edit(state, { payload }) {
				return { ...state, currentItem: payload };
			},
			add(state, { payload }) {
				return { ...state, list: state.list.concat(payload), currentItem: null };
			},
			updateOne(state, { payload }) {
				const list = state.list.map(t => t.id === payload.id ? { ...t, ...payload } : t);
				return { ...state, list, currentItem: null };
			},
			remove(state, { id, ids }) {
				id = typeof id == 'object' ? id[0] : id;
				const list = ids
					? state.list.filter(t => !ids.includes(t.id))
					: state.list.filter(t => t.id !== id);
				// console.log()
				return { ...state, list };
			},
			list(state, { list }) {
				return { ...state, list };
			},
			set(state, { payload, type, ...other }) {
				return { ...state, ...payload, ...other };
			},
			setObj(state, { key, value }) {
				return { ...state, [key]: { ...state[key], ...value } };
			}
		},
	});

	const keys = ['state', 'subscriptions', 'effects', 'reducers'];
	const newModel = { ...base, ...model };
	keys.forEach(k => newModel[k] = { ...base[k], ...model[k] });
	return newModel;
}

export function delay(timeout = 10000) {
	return new Promise(res => {
		setTimeout(() => res(true), timeout);
	});
}
